package sign

import (
	"context"
	"errors"
	"github.com/gorilla/websocket"
	"net/url"
	ap "sieve_admin_server_userpass/pkg/app"
	"sieve_admin_server_userpass/pkg/im3/app"
	"sieve_admin_server_userpass/pkg/im3/crypto"
	"sieve_admin_server_userpass/pkg/json"
	"strconv"
	"time"
)

func MakeUid(uid int) (string, error) {
	return crypto.AesEncrypt(app.Secret(), []byte(strconv.Itoa(uid)))
}

func reqSignCtx(ctx context.Context, uid int, content string) (string, error) {
	v := url.Values{}
	v.Set("appid", strconv.Itoa(app.AppId()))
	suid, err := MakeUid(uid)
	if err != nil {
		return "", err
	}
	v.Set("uid", suid)
	v.Set("content", content)
	conn, _, err := websocket.DefaultDialer.Dial("wss://"+app.Server()+"/sign/request?"+v.Encode(), nil)
	if err != nil {
		return "", err
	}
	defer conn.Close()

	ch := make(chan interface{})
	ap.Async(func() {
		_, b, err := conn.ReadMessage()
		if err != nil {
			ch <- err
		} else {
			ch <- b
		}
	})
	select {
	case v := <-ch:
		switch vv := v.(type) {
		case error:
			return "", vv
		case []byte:
			m := map[string]string{}
			if err := json.Unmarshal(vv, &m); err != nil {
				return "", err
			}
			sign := m["sign"]
			if sign == "" {
				return "", errors.New("reject")
			}
			return sign, nil
		default:
			return "", errors.New("unknown type")
		}
	case <-ctx.Done():
		return "", ctx.Err()
	}
}

func ReqSign(uid int, content string) (string, error) {
	return reqSignCtx(ap.CTX, uid, content)
}

func ReqSignWithTimeout(uid int, content string, timeout time.Duration) (string, error) {
	ctx, _ := context.WithTimeout(ap.CTX, timeout)
	return reqSignCtx(ctx, uid, content)
}
